package com.cxyd.modules.wcs.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.cxyd.common.service.impl.CrudServiceImpl;
import com.cxyd.common.utils.ConvertUtils;
import com.cxyd.modules.log.service.SysLogWorkService;
import com.cxyd.modules.wcs.dao.ReceiveTaskDao;
import com.cxyd.modules.wcs.dto.ReceiveTaskDTO;
import com.cxyd.modules.wcs.entity.AgvTrkEntity;
import com.cxyd.modules.wcs.entity.ReceiveTaskEntity;
import com.cxyd.modules.wcs.entity.RouteCtuEntity;
import com.cxyd.modules.wcs.entity.TrkEntity;
import com.cxyd.modules.wcs.service.AgvTrkService;
import com.cxyd.modules.wcs.service.ReceiveTaskService;
import com.cxyd.modules.wcs.service.RouteCtuService;
import com.cxyd.modules.wcs.service.TrkService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.Duration;
import java.time.Instant;
import java.util.*;

/**
 * 接收指令信息
 *
 * @author Cycle gengruyi01@163.com
 * @since 1.0.0 2022-11-14
 */
@Service
public class ReceiveTaskServiceImpl extends CrudServiceImpl<ReceiveTaskDao, ReceiveTaskEntity, ReceiveTaskDTO> implements ReceiveTaskService {
    @Resource
    private TrkService trkService;
    @Resource
    private AgvTrkService agvTrkService;
    @Resource
    private RouteCtuService ctuRouteService;
    @Resource
    private SysLogWorkService logWorkService;

    /**
     * 搜索框条件拼接
     */
    @Override
    public QueryWrapper<ReceiveTaskEntity> getWrapper(Map<String, Object> params) {
        String requestPk = (String) params.get("requestPk");
        String contNo = (String) params.get("contNo");
        String trkType = (String) params.get("trkType");
        String frmPos = (String) params.get("frmPos");
        String toPos = (String) params.get("toPos");
        String groupNo = (String) params.get("groupNo");
        String status = (String) params.get("status");
        String startDate = (String) params.get("startDate");
        String endDate = (String) params.get("endDate");

        QueryWrapper<ReceiveTaskEntity> wrapper = new QueryWrapper<>();
        wrapper.eq(StringUtils.isNotBlank(requestPk), "request_pk", requestPk);
        wrapper.eq(StringUtils.isNotBlank(status), "status", status);
        wrapper.eq(StringUtils.isNotBlank(contNo), "cont_no", contNo);
        wrapper.eq(StringUtils.isNotBlank(trkType), "trk_type", trkType);
        wrapper.eq(StringUtils.isNotBlank(groupNo), "group_no", groupNo);
        wrapper.like(StringUtils.isNotBlank(frmPos), "frm_pos", frmPos);
        wrapper.like(StringUtils.isNotBlank(toPos), "to_pos", toPos);

        wrapper.ge(StringUtils.isNotBlank(startDate), "req_time", startDate);
        wrapper.le(StringUtils.isNotBlank(endDate), "req_time", endDate);

        return wrapper;
    }

    @Override
    public ReceiveTaskDTO getOneByPk(Map<String, Object> params) {
        String requestPk = (String) params.get("requestPk");
        final ReceiveTaskEntity entity = baseDao.getOneByPk(requestPk);
        return ConvertUtils.sourceToTarget(entity, ReceiveTaskDTO.class);
    }

    @Override
    public ReceiveTaskDTO getOneByContNo(Map<String, Object> params) {
        String contNo = (String) params.get("contNo");
        final ReceiveTaskEntity entity = baseDao.getOneByContNo(contNo);
        return ConvertUtils.sourceToTarget(entity, ReceiveTaskDTO.class);
    }

    @Override
    public ReceiveTaskDTO getOneByCondition(Map<String, Object> params) {
        return null;
    }

    @Override
    public ReceiveTaskDTO getOneBySt() {
//        1.入库任务优先解析
        QueryWrapper<ReceiveTaskEntity> qw = new QueryWrapper<>();
        qw.lambda().eq(ReceiveTaskEntity::getStatus, 0)
                .isNotNull(ReceiveTaskEntity::getContNo)
                .orderBy(true, true, ReceiveTaskEntity::getTrkType)
                .orderBy(true, false, ReceiveTaskEntity::getTrkPrty)
                .last("limit 1");
        ReceiveTaskEntity entity = baseDao.selectOne(qw);
        return ConvertUtils.sourceToTarget(entity, ReceiveTaskDTO.class);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void analyzeHandler(ReceiveTaskDTO dto) {
        String workName = "指令解析";
        String workProc = "ReceiveTaskService.analyzeHandler";
        String pCode = "0";
        String pMsg;
        String contNo = dto.getContNo();
        int status;
        ReceiveTaskEntity receiveTaskEntity = ConvertUtils.sourceToTarget(dto, ReceiveTaskEntity.class);
        if (StringUtils.isBlank(contNo)) {
            status = 9;
//            更新[wcs_receive_task]的状态
            pCode = "analyze_error_001";
            pMsg = "指令解析异常!料箱条码不能为空!";
            receiveTaskEntity.setStatus(status);
            receiveTaskEntity.setComments(pCode + ":" + pMsg);
            receiveTaskEntity.setUpdateDate(new Date());
            baseDao.updateById(receiveTaskEntity);
//            记录日志
            logWorkService.workLogging(workName, contNo, pCode, pMsg, "", workProc, "WCS系统", 0);
            return;
        }
//        1.开始对任务进行解析
        TrkEntity existsEntity = trkService.selectByContNo(contNo);
        if (existsEntity != null) {
            status = 9;
            pCode = "analyze_error_002";
            pMsg = "指令解析异常!料箱[" + contNo + "]在[wcs_trk]表中已存在任务[" + existsEntity.getTrkId() + "]!";
            receiveTaskEntity.setStatus(status);
            receiveTaskEntity.setComments(pCode + ":" + pMsg);
            receiveTaskEntity.setUpdateDate(new Date());
            baseDao.updateById(receiveTaskEntity);
//            记录日志
            logWorkService.workLogging(workName, contNo, pCode, pMsg, "", workProc, "WCS系统", 0);
            return;
        }

        RouteCtuEntity ctuRoute = ctuRouteService.getTaskTypByCondition(dto.getTrkType(), dto.getFrmPos(), dto.getToPos());
        if (ctuRoute == null) {
//            未配置对应搬送模板
            status = 9;
            pCode = "analyze_error_003";
            pMsg = "指令解析异常!未配置对应搬送模板!";
            receiveTaskEntity.setStatus(status);
            receiveTaskEntity.setComments(pCode + ":" + pMsg);
            receiveTaskEntity.setUpdateDate(new Date());
            baseDao.updateById(receiveTaskEntity);
//            记录日志
            logWorkService.workLogging(workName, contNo, pCode, pMsg, "", workProc, "WCS系统", 0);
            return;
        }
        Instant start = Instant.now();
//        2.根据起始位置与目标位置匹配搬送模板
        TrkEntity trkEntity = ConvertUtils.sourceToTarget(dto, TrkEntity.class);

        trkEntity.setTrkPrty(Integer.valueOf(dto.getTrkPrty()));
        trkEntity.setDvcNo(ctuRoute.getWbCode());
        trkEntity.setCurPos(dto.getFrmPos());
        trkEntity.setCreator(1001L);
        trkEntity.setCreateDate(new Date());
        trkEntity.setUpdater(1001L);
//        3.数据写入[WCS_TRK]表
        trkService.insert(trkEntity);
        Long trkId = trkEntity.getTrkId();
//        数据写入[CTU_TRK]表(taskCode使用有含义的编码规则:托盘条码+年月日+6位trkId)
        String yyyyMMdd = DateUtil.format(new Date(), "yyyyMMdd");
        String taskCode = contNo + yyyyMMdd + StrUtil.padPre(String.valueOf(trkId), 6, '0');
//        防止reqCode重复，使用料箱码+时间戳
        String reqCode = contNo + System.currentTimeMillis();
//        构建搬送路径(路径在下发CTU时再构建)

//        容器类型,大容器=2,其他容器=1
        String ctnrTyp = "2";
        if ("1".equals(dto.getContType())) {
            ctnrTyp = "1";
        }

        String taskMode = "0";
        AgvTrkEntity agvTrkEntity = new AgvTrkEntity();
        agvTrkEntity.setTrkId(trkId);
//        wbCode用于记录工作台位置
        agvTrkEntity.setPriority(dto.getTrkPrty());
        agvTrkEntity.setWbCode(ctuRoute.getWbCode());
        agvTrkEntity.setReqCode(reqCode);
        agvTrkEntity.setTaskCode(taskCode);
        agvTrkEntity.setTaskTyp(ctuRoute.getTaskTyp());
//        CTU装载的容器编号
        agvTrkEntity.setCtnrCode(contNo);
        agvTrkEntity.setCtnrTyp(ctnrTyp);
        agvTrkEntity.setTaskMode(taskMode);
        agvTrkService.insert(agvTrkEntity);
//        处理完成更新[wcs_receive_task]表数据
        status = 1;
        pMsg = "[step-1]料箱[" + contNo + "]任务解析完成!起始点[" + dto.getFrmPos() + "],目的地[" + dto.getToPos() + "]生成搬送任务[" + trkId + "]";
        receiveTaskEntity.setStatus(status);
        receiveTaskEntity.setComments(pCode + ":" + pMsg);
        receiveTaskEntity.setUpdateDate(new Date());
        baseDao.updateById(receiveTaskEntity);
//        计算耗时
        Instant end = Instant.now();
        Duration times = Duration.between(start, end);

//        4.日志记录
        logWorkService.workLogging(workName, dto.getContNo(), pCode, pMsg, "", workProc, "WCS系统", times.toMillis());
    }

    @Override
    public boolean updateReceiveTaskByPrty(ReceiveTaskDTO dto, ReceiveTaskDTO old) {
//        判断并更更新receiveTask的优先级
        if (!dto.getRequestPk().equals(old.getRequestPk())) {
            return false;
        }
//        更新接收到的任务优先级
        UpdateWrapper<ReceiveTaskEntity> uw = new UpdateWrapper<>();
        uw.lambda().set(ReceiveTaskEntity::getTrkPrty, dto.getTrkPrty())
                .set(ReceiveTaskEntity::getComments, "优先级调整")
                .eq(ReceiveTaskEntity::getRequestPk, old.getRequestPk());
        baseDao.update(null, uw);
        if (old.getStatus() > 0) {
            TrkEntity trkEntity = trkService.selectByContNo(old.getContNo());
            if (trkEntity != null) {
                trkEntity.setTrkPrty(Integer.valueOf(dto.getTrkPrty()));
                trkService.updateById(trkEntity);
            }
            AgvTrkEntity agvEntity = agvTrkService.getAgvTrkByContNo(old.getContNo());
            if (agvEntity != null) {
                agvEntity.setPriority(dto.getTrkPrty());
                agvTrkService.updateById(agvEntity);
            }
        }
        return true;
    }

    @Override
    public void updateReceiveTaskByContNo(String contNo) {
        QueryWrapper<ReceiveTaskEntity> qw = new QueryWrapper<>();
        qw.lambda().eq(ReceiveTaskEntity::getContNo, contNo)
                .gt(ReceiveTaskEntity::getStatus, 0);
        ReceiveTaskEntity receiveTaskEntity = baseDao.selectOne(qw);
        receiveTaskEntity.setStatus(2);
        receiveTaskEntity.setUpdateDate(new Date());
        baseDao.updateById(receiveTaskEntity);
//        转移数据至历史并删除表数据
        baseDao.backupReceiveTask(contNo);
        baseDao.deleteById(receiveTaskEntity);
    }
}